#!/bin/bash

# - _git_url
# - _languages
# - _versions

. $LKP_SRC/lib/debug.sh
. $LKP_SRC/lib/upload.sh
. $LKP_SRC/lib/rpm.sh
. $LKP_SRC/lib/email.sh

. $LKP_SRC/lib/job.sh
load_job_vars SRV_HTTP_GIT_HOST SRV_HTTP_GIT_PORT _git_url _languages _versions

: "${_languages:=C,C++,Rust,Python,Java,JavaScript,TypeScript,Perl}"

system_uname=$(uname -m )
[ ${system_uname} = "aarch64" ] && has_procenv=False 
[ ${system_uname} = "x86_64" ] && has_procenv=True
execute_dir="/root/execute"
rpmdev_dir="${execute_dir}/build_result"
npmrc_dir="/root/.npmrc"

src_upstream_repo="https://${SRV_HTTP_GIT_HOST}:${SRV_HTTP_GIT_PORT:-20010}/git/src-upstream/github.com"
#upstream_repo="git://${SRV_HTTP_GIT_HOST}:9418/upstream/github.com"
#upstream_repo="git://172.168.177.202:9418/upstream/github.com"
upstream_autospec_repo="git://${SRV_HTTP_GIT_HOST}:9418/upstream/gitee.com/autospec"
git_clone_form_cache_url="http://172.168.178.72"

namespace=$(echo $_git_url | awk -F'/' '{print $4}')
reponame_git=$(echo $_git_url | awk -F'/' '{print $5}')
reponame=${reponame_git::-4}

declare -a reverse_depends
die()
{
	echo "fail"
	echo "$@"
	exit 99
}

mkdir_and_mount_execut_dir()
{
	mkdir -p "${execute_dir}"
	mount -t tmpfs tmpfs "${execute_dir}"
	cd ${execute_dir}
}

pip_switch_source()
{
	pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
}

modules=("coverage" "requests" "flake8" "virtualenv" "toml" "mock" "pycurl" "scancode-toolkit" "PyYaml")
check_module()
{
	for module in "${modules[@]}"; do
		if ! pip show "$module" > /dev/null 2>/dev/null; then
			echo "not module $module, begin pip install $module"
			pip install --user --quiet $module -i http://${SRV_HTTP_GIT_HOST}:5032/lowinli/devpi/+simple/ --trusted-host ${SRV_HTTP_GIT_HOST}:5032 2>/dev/null
		fi
	done
}

init_tools()
{
	# yum install -y mock
	[ ${system_uname} = "x86_64" ] && yum install -y procenv 
	# pip3 install --user setuptools wheel scancode-toolkit
	check_module
	set_mock
}

add_repo_additonal()
{
	cat <<-EOF >> /etc/yum.repos.d/compatiblef33.repo
	[compatiblef33]
	name=compatiblef33
	baseurl=https://repo.oepkgs.net/openeuler/rpm/openEuler-22.03-LTS/compatible/f33/${system_uname}/
	enabled=1
	gpgcheck=0
	priority=100
	EOF
}

set_mock()
{
	cat <<-EOF >> /etc/mock/clear.cfg
	config_opts['chroot_setup_cmd'] = 'install rpm-build gcc make git nasm yasm g++ virtualenv maven python3-devel nodejs go bison rsync'
	config_opts['package_manager'] = 'dnf'
	config_opts['more_buildreqs'] = 'gdb-headless'
	config_opts['plugin_conf']['root_cache_enable'] = False
	config_opts['plugin_conf']['selinux_enable'] = False
	config_opts['plugin_conf']['procenv_enable'] = ${has_procenv}
	config_opts['nosync'] = True

	config_opts['root'] = 'openEuler-LTS-${system_uname}-1'

	config_opts['target_arch'] = '${system_uname}'
	config_opts['use_bootstrap'] = False
	config_opts['dnf_disable_plugins'] = ['local', 'spacewalk']
	config_opts['use_nspawn'] = False
	config_opts['useradd'] = '/usr/sbin/useradd -m -u {{chrootuid+500}} -g {{chrootgid}} -d {{chroothome}}  {{chrootuser}}'

	config_opts['yum.conf'] = """

	[main]
	cachedir=/var/cache/dnf
	keepcache=1
	debuglevel=1
	reposdir=/dev/null
	logfile=/var/log/dnf.log
	retries=20
	obsoletes=1
	gpgcheck=0
	assumeyes=1
	syslog_ident=mock
	syslog_device=

	# repos

	[OS]
	name=OS
	baseurl=https://repo.openeuler.org/openEuler-22.03-LTS/OS/${system_uname}/
	enabled=1
	gpgcheck=1
	gpgkey=https://repo.openeuler.org/openEuler-22.03-LTS/OS/${system_uname}/RPM-GPG-KEY-openEuler

	[everything]
	name=everything
	baseurl=https://repo.openeuler.org/openEuler-22.03-LTS/everything/${system_uname}/
	enabled=1
	gpgcheck=1
	gpgkey=https://repo.openeuler.org/openEuler-22.03-LTS/everything/${system_uname}/RPM-GPG-KEY-openEuler

	[EPOL]
	name=EPOL
	baseurl=https://repo.openeuler.org/openEuler-22.03-LTS/EPOL/main/${system_uname}/
	enabled=1
	gpgcheck=1
	gpgkey=https://repo.openeuler.org/openEuler-22.03-LTS/OS/${system_uname}/RPM-GPG-KEY-openEuler

	[debuginfo]
	name=debuginfo
	baseurl=https://repo.openeuler.org/openEuler-22.03-LTS/debuginfo/${system_uname}/
	enabled=1
	gpgcheck=1
	gpgkey=https://repo.openeuler.org/openEuler-22.03-LTS/debuginfo/${system_uname}/RPM-GPG-KEY-openEuler

	[source]
	name=source
	baseurl=https://repo.openeuler.org/openEuler-22.03-LTS/source/
	enabled=1
	gpgcheck=1
	gpgkey=https://repo.openeuler.org/openEuler-22.03-LTS/source/RPM-GPG-KEY-openEuler

	[update]
	name=update
	baseurl=https://repo.openeuler.org/openEuler-22.03-LTS/update/${system_uname}/
	enabled=1
	gpgcheck=1
	gpgkey=https://repo.openeuler.org/openEuler-22.03-LTS/OS/${system_uname}/RPM-GPG-KEY-openEuler

	[extras]
	name=extras
	baseurl=https://repo.oepkgs.net/openEuler/rpm/openEuler-22.03-LTS/extras/${system_uname}/
	enabled=1
	gpgcheck=0
	priority=100

	[extras-source]
	name=extras-source
	baseurl=https://repo.oepkgs.net/openeuler/rpm/openEuler-22.03-LTS/compatible/f33/${system_uname}/
	enabled=1
	gpgcheck=0
	priority=100

	"""

	EOF

	sed -i 's/repo.openeuler.org/mirrors.huaweicloud.com\/openeuler/g' /etc/mock/clear.cfg
}

set_npmrc()
{
	cat <<-EOF >> ${npmrc_dir}
	strict-ssl=false
	electron_mirrir=http://mirrors.tools.huawei.com/electron/
	EOF
}
	
config=("CONFIG" "configure" "configure.ac" "configure.in" "zclocal.m4" "Makefile.am" "Makefile.in" "config.in" "CMakeLists.txt") 
check_repo_file()
{
	local filename

	for filename in "${config[@]}";do
		test -e ${execute_dir}/${reponame}/${filename} && return 0
	done

	find "${execute_dir}/${reponame}" -name "*CMakeLists.txt*" -print && return 0


	if [ -e ${execute_dir}/${reponame}/Makefile ];then
		grep "install" ${execute_dir}/${reponame}/Makefile && return 0 
	fi

	echo "This repo does not have configure and Makefile!"
	echo "git_url: $_git_url"
	return 1
}

find_top_language()
{
   	# Use find command to get all files in the directory
  	# Pipe the output to awk to extract file suffixes and map to programming languages
    	# Then use sort and uniq -c to count occurrences of each language
	local top_language_line=$(find "${execute_dir}/${reponame}" -type f | awk -F. -f $LKP_SRC/programs/autospec/top-lang.awk | sort -rn | head -n 1)

	# Extract and display the top programming language
	local top_language=$(echo "$top_language_line" | awk '{print $2}')
	[ -z "${top_language}" ] && return 1
	echo "main programming language: ${top_language}"

	[[ "${_languages#*$top_language}" = "${_languages}" ]] && return 1

	return 0
}

do_extra_work_by_language()
{
	# ruby-common will rewrite ruby's macros macro definition, change the construction logic
	# remove from fulleuler
	[[ "$1" = "Ruby" ]] && chroot /mnt/merged/ yum remove ruby-common -y
}

build_repo_tar_gz()
{
	tar_name=$1
	[[ $tar_name == */* ]] && tar_name=$(echo ${tar_name} | sed 's/\//_/g')
	
	mkdir -p ${rpmdev_dir}/$tar_name

	tar_gz_name="$tar_name.tar.gz"
	cd ${execute_dir}/${reponame}
	git checkout -q $1
	cd ${execute_dir}
	tar czf ${rpmdev_dir}/$tar_name/${tar_gz_name} ${reponame}

	[ -f ${rpmdev_dir}/$tar_name/${tar_gz_name} ] || return 1
	return 0
}

get_first_two_chars()
{
	echo "${1:0:2}" | awk '{gsub(/[^a-zA-Z]/,"_"); print tolower($0)}'
}

git_clone(){
	echo "try clone git_url: $_git_url"
	local count=1
	local prefix_reponame=$(get_first_two_chars $reponame)

	git_clone_url="${git_clone_form_cache_url}/${prefix_reponame}/${namespace}/${reponame}.git"
	echo "${git_clone_url}"

	while [ $count -le 5 ]; do
		count=$((count+1))
		git clone -q ${git_clone_url} && return 0
	done
	echo "git clone repo failed: $reponame"
	return 1

}


config_repo()
{
	cd ${execute_dir}/${reponame}
	git config advice.detachedHead false
	cd ${execute_dir}
}


autospec_from_git()
{
	local count=1
	while [ $count -le 5 ]; do
		count=$((count+1))
		git clone -q "$upstream_autospec_repo/autospec.git" && return 0
	done
	echo "git clone autospec failed: $upstream_autospec_repo/autospec.git"
	return 1
}

add_user_mock()
{
	groupadd mock
}

start_build()
{
	echo "begin autospec"
	cd ${execute_dir}/autospec/autospec
 	python3 autospec.py -g -t ${rpmdev_dir}/$tar_name ${rpmdev_dir}/$tar_name/$tar_gz_name -n $reponame -v $1 

}

record_rpm_files_to_list()
{
	find ${rpmdev_dir}/results -type f -name "*.rpm" -print0 | xargs -0 -I {} basename {} > $TMP/rpm.list
}

record_src_rpm_files()
{
 	#find ${rpmdev_dir}/results -type f -name "*.src.rpm" -print0 | xargs -0 -I {} basename {} > $TMP/src.rpm.list
	local src_rpm_files=$(find ${rpmdev_dir}/$tar_name -type f -name "*.src.rpm" -print0 |  xargs -0 -I {} echo "{}")
        for src_rpm_file in ${src_rpm_files}
        do
                upload_one_curl ${src_rpm_file} ${result_root}/$tar_name
        done

}

record_rpm_files()
{
	local rpm_files=$(find ${rpmdev_dir}/$tar_name -type f -name "*.rpm" -print0 |  xargs -0 -I {} echo "{}")
        for rpm_file in ${rpm_files}
        do
                upload_one_curl ${rpm_file} ${result_root}/$tar_name
        done

 }

record_spec_files()
{
	local spec_files=$(find ${rpmdev_dir}/$tar_name -type f -name "*.spec" -print0 |  xargs -0 -I {} echo "{}")
        for spec_file in ${spec_files}
        do
                upload_one_curl ${spec_file} ${result_root}/$tar_name
        done
}

record_log_files()
{
	local log_files=$(find ${rpmdev_dir}/$tar_name -type f -name "*.log" -print0 | xargs -0 -I {} echo "{}")
        for log_file in ${log_files}
        do
                upload_one_curl ${log_file} ${result_root}/$tar_name
		[[ "${log_file##*/}" = build.log ]] && cp --no-clobber ${log_file} $RESULT_ROOT
        done
}


upload_rpm_pkg()
{
        local rpm_file
	set nullglob
        for rpm_file in ${rpmdev_dir}/results/*.rpm
        do
                upload_one_curl ${rpm_file} ${result_root}
        done


        local src_rpm_file
        set nullglob
	for src_rpm_file in ${rpmdev_dir}/results/*.src.rpm
        do
                upload_one_curl ${src_rpm_file} ${result_root}
        done

}

upload_spec_file()
{
        local spec_file
 	set nullglob
	for spec_file in ${rpmdev_dir}/*.spec
        do
                upload_one_curl ${spec_file} ${result_root}
        done
}

execute_autospec()
{
	build_repo_tar_gz $1 || echo_and_exit_code 252
	start_build $1
	local exit_code=$?
	cd ${execute_dir}

	record_log_files
	record_src_rpm_files
	record_spec_files

	if [ $exit_code -eq 0 ]
	then
		record_rpm_files
		#upload_spec_file $1
		#upload_rpm_pkg $1
		exit 0
	else
		rm -rf ${rpmdev_dir}/$1
		echo "AUTOSPEC_FAILED: ${exit_code}"
	fi
 
}

get_version_from_repo()
{
	version_list=()
	local tag_or_branch_array=()

	# get repo tags and dates or branch and latest commit time.
	# sorted by time and put into tag_or_branch_array, get latest 5 records.
	cd ${execute_dir}/${reponame}

	tag_or_branch_array=($(git for-each-ref --sort=-creatordate --format='%(creatordate:short):%(refname:short)' refs/tags | sort -ur | head -n 5))

	[ ${#tag_or_branch_array[@]} -eq 0 ] && tag_or_branch_array=($(git for-each-ref --sort=-committerdate --format='%(committerdate:short):%(objectname:short)' refs/remotes/origin | sort -ur | head -n 5))

	cd ${execute_dir}

	[ ${#tag_or_branch_array[@]} -eq 0 ] && return 1

	# get version that is submitted 3 years after 
	# the latest submission time based on the time information
	# in the tag_or_branch_array
	local newest_time=$(date -d "$(echo ${tag_or_branch_array[0]} | cut -d ':' -f 1)" +%s)
	for item in "${tag_or_branch_array[@]}"; do 
		local item_time=$(date -d "$(echo $item | cut -d ':' -f 1)" +%s)
		(( (newest_time - item_time) <=  ( 3 * 365 * 24 * 3600 ) )) && 
			local version=$(echo $item | cut -d ':' -f 2) && 
			[[ ${version:0:5} == "tags/" ]] && version=${version:5:}
		version_list+=("$version")
	done

	return 0
}

get_versions_to_autospec()
{
	if [ -n "${_versions}" ]; then
		version_list=($(echo ${_versions} | tr ',' '\n'))
	else
		get_version_from_repo || echo_and_exit_code 247 
	fi

	for version in "${version_list[@]}"; do
		echo "begin version: ${version}"
		execute_autospec "${version}"
	done
}

echo_and_exit_code()
{
	echo "run_exit_code: $1"
	exit "$1"
}

mount_nfs_ro()
{
    yum install -y nfs-utils
    mkdir -p /mnt/nfs
    mount -t nfs -o ro 172.168.131.2:os-rw /mnt/nfs
}

mount_overlayfs_rw()
{
	mkdir -p /mnt/upperdir
	mkdir -p /mnt/workdir
	mkdir -p /mnt/merged
	mount -t overlay overlay -o lowerdir=/mnt/nfs/openeuler/${system_uname}/22.03-LTS-autospec,upperdir=/mnt/upperdir,workdir=/mnt/workdir /mnt/merged
}

mv_gcc()
{
	mv /mnt/merged/usr/bin/gcc /mnt/merged/usr/bin/gcc.bak
	mv /mnt/merged/usr/bin/gcc_old /mnt/merged/usr/bin/gcc
	mv /mnt/merged/usr/bin/c++ /mnt/merged/usr/bin/c++.bak
	mv /mnt/merged/usr/bin/c++_old /mnt/merged/usr/bin/c++
	mv /mnt/merged/usr/bin/g++ /mnt/merged/usr/bin/g++.bak
	mv /mnt/merged/usr/bin/g++_old /mnt/merged/usr/bin/g++
}
#add_repo
#yum_repo_retry
echo "start autospec rpmbuild"

mkdir_and_mount_execut_dir
add_repo_additonal
pip_switch_source
init_tools
add_user_mock
set_npmrc
autospec_from_git || echo_and_exit_code 253

cd ${execute_dir}/autospec
autospec_commit=$(git log --pretty=oneline -n 1)
cd ${execute_dir}
echo "autospec commit id: $autospec_commit"
 
mount_nfs_ro
mount_overlayfs_rw
mv_gcc

git_clone || echo_and_exit_code 253
config_repo
check_repo_file || echo_and_exit_code 249

find_top_language || echo_and_exit_code 251 
do_extra_work_by_language ${top_language}

get_versions_to_autospec
echo "end autospec rpmbuild"	
echo "git_url: $_git_url"
echo_and_exit_code 254

# exit code
# 254 : failed to pack all versions
# 253 : git clone failed
# 252 : build tar.gz failed
# 251 : main language is not in the trustlist
# 249 : no build language found
# 247 : no found version

